Repository navigation
feat(bot): add playtop, playskip, skipto, seek, replay and pause/resume toggle - #522
Conversation
…ause/resume toggle
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthroughConverted multiple music commands: Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Size Change: 0 B Total Size: 324 kB ℹ️ View Unchanged
|
- creates play/queryutils.ts with discord_unknown_interaction_code, isunknowninteractionerror, isurl, and resolvesearchengine - removes duplicate utilities from playtop.ts and playskip.ts - adds comprehensive execute logic tests for playtop and playskip - increases coverage from 2 tests (command structure) to 12+ tests covering error cases, queue operations, and success scenarios - seek.spec.ts already has full test coverage
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (8)
packages/bot/src/functions/music/commands/playtop.spec.ts (1)
53-64: These assertions miss the actualplaytopcontract.Right now the spec only checks builder shape. It won't catch regressions where
execute()fails to queue the new track first or replies with the wrong result. Please cover the ordering behavior itself. As per coding guidelines, "Test behavior, not implementation details" and "Prefer unit tests for core logic; add integration tests at meaningful boundaries".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/functions/music/commands/playtop.spec.ts` around lines 53 - 64, The test currently only asserts the playTopCommand shape; add behavioral tests for playTopCommand.execute to ensure it enqueues the new track at the front and replies with the correct result: mock/stub the player/queue and a message interaction, call playTopCommand.execute with an existing queue (and with an empty queue) and assert that the new track appears at index 0 in the queue and that interaction.reply (or the command's reply method) is called with the expected success message; reference playTopCommand.execute and the queue/player mock to locate where to inject these assertions.packages/bot/src/functions/music/commands/replay.spec.ts (1)
59-63: Theno current trackcase is exercising an impl-only state.Lines 59-63 make
requireCurrentTracksucceed globally, so Lines 97-105 only pass because the test bypasses the real validator contract. That leaves the meaningful branches here under-covered. I’d switch this case to assert the early return whenrequireCurrentTrackis false, and add a paused-queue case once the command semantics are settled. As per coding guidelines, "Test behavior, not implementation details" and "Prefer unit tests for core logic; add integration tests at meaningful boundaries".Also applies to: 97-105
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/functions/music/commands/replay.spec.ts` around lines 59 - 63, The test currently forces requireCurrentTrack to succeed globally (requireCurrentTrackMock.mockResolvedValue(true)), which hides the "no current track" branch; change the specific "no current track" spec to set requireCurrentTrackMock.mockResolvedValue(false) (while keeping other validators as needed) and assert that the command returns/early-exits (e.g., checks for the expected reply or no-op) instead of relying on implementation state; also add a separate spec that simulates a paused queue by adjusting requireIsPlayingMock (or the queue mock) to reflect a paused state and assert the paused-queue behavior once command semantics are finalized.packages/bot/src/functions/music/commands/playskip.spec.ts (1)
53-64: These tests only pin slash metadata, notplayskipbehavior.Lines 53-64 will still pass if
execute()stops inserting the new track at the front or stops skipping immediately, which are the risky parts of this feature. Please add at least one execution-path test that asserts the queue mutation and skip side effect. As per coding guidelines, "Test behavior, not implementation details" and "Prefer unit tests for core logic; add integration tests at meaningful boundaries".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/functions/music/commands/playskip.spec.ts` around lines 53 - 64, Add an execution-path test in playskip.spec.ts that exercises playSkipCommand.execute instead of only verifying slash metadata: invoke playSkipCommand.execute with a mocked command context containing a "query" option and a fake player/queue, stub the queue mutation and skip methods (e.g., the queue insertion function and the player's skip/next method), then assert that the new track was inserted at the front of the queue (index 0) and that the skip/next method was called once; use test doubles/spies to verify both the queue mutation and the immediate skip side effect rather than inspecting internal implementation details.packages/bot/src/functions/music/commands/playtop.ts (2)
84-84: Useconstinstead ofletfor variables that are not reassigned.
resultis never reassigned after initialization.♻️ Suggested fix
- let result = await client.player.play(voiceChannel, query, { + const result = await client.player.play(voiceChannel, query, {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/functions/music/commands/playtop.ts` at line 84, The variable declaration for result (assigned from client.player.play in playtop.ts) uses let but is never reassigned; change its declaration to const to reflect immutability—locate the assignment to result (let result = await client.player.play(voiceChannel, query, { ... })) and replace let with const so the variable is read-only.
16-34: Extract duplicated helper functions to a shared utility.
isUnknownInteractionError,isUrl, andresolveSearchEngineare duplicated acrossplaytop.ts,playskip.ts, andplay/index.ts. Additionally,play/index.tshas a more completeresolveSearchEnginethat supports aproviderparameter, while the other two only acceptquery. Extract these to a shared module (e.g.,utils/music/searchEngine.tsorutils/general/discordErrors.ts) to follow DRY principles and enable reuse of the enhancedresolveSearchEnginesignature.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/functions/music/commands/playtop.ts` around lines 16 - 34, The helpers isUnknownInteractionError, isUrl, and resolveSearchEngine are duplicated and should be extracted into a shared utility; create a new module (e.g., utils/music/searchEngine or utils/general) that exports isUnknownInteractionError, isUrl, and the enhanced resolveSearchEngine signature (accepting query and optional provider like the version in play/index.ts), replace the local definitions in playtop.ts (and similarly in playskip.ts and play/index.ts) with imports from that module, and update call sites to use the unified resolveSearchEngine(provider?, query?) API so all three files reuse the single implementation.packages/bot/src/functions/music/commands/skipto.ts (1)
52-52: Unnecessary optional chaining after validation.
queueis guaranteed to exist here sincerequireQueuewould have returned early otherwise. The optional chainingqueue?.node.skipTois redundant and slightly obscures the control flow.♻️ Suggested simplification
- queue?.node.skipTo(targetIndex) + queue.node.skipTo(targetIndex)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/functions/music/commands/skipto.ts` at line 52, The optional chaining on queue is unnecessary because requireQueue ensures queue exists; replace the call queue?.node.skipTo(targetIndex) with a direct call queue.node.skipTo(targetIndex) in skipto.ts (the code path after requireQueue) to simplify control flow and remove the redundant ?. Keep the same targetIndex and error handling unchanged.packages/bot/src/functions/music/commands/playskip.ts (1)
83-83: Useconstinstead oflet.
resultis not reassigned.♻️ Suggested fix
- let result = await client.player.play(voiceChannel, query, { + const result = await client.player.play(voiceChannel, query, {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/functions/music/commands/playskip.ts` at line 83, The variable "result" declared in the playskip command is never reassigned; change its declaration from "let result = await client.player.play(voiceChannel, query, { ... })" to use "const" instead to reflect immutability and prevent accidental reassignment; update the declaration where "result" is created in playskip.ts (the client.player.play call) to use const.packages/bot/src/functions/music/commands/skipto.spec.ts (1)
60-122: Consider adding a test for queue validation failure.The test suite covers voice channel validation failure (line 68-76) but doesn't test the early return when
requireQueuereturns false. Adding this case would ensure complete coverage of the validation paths.it('returns early when queue validation fails', async () => { requireQueueMock.mockResolvedValue(false) const queue = createQueue([{ id: 'track-1' }]) resolveGuildQueueMock.mockReturnValue({ queue }) await skiptoCommand.execute({ client: createClient(), interaction: createInteraction() } as any) expect(queue.node.skipTo).not.toHaveBeenCalled() })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/functions/music/commands/skipto.spec.ts` around lines 60 - 122, Add a new unit test that asserts the command returns early when queue validation fails by mocking requireQueueMock to resolve false, calling skiptoCommand.execute with a mocked interaction (use createInteraction) and a resolved guild queue (resolveGuildQueueMock -> { queue } from createQueue), and then asserting queue.node.skipTo was not called; target the same pattern used in the existing voice-channel-failure test and reference requireQueueMock, skiptoCommand.execute, resolveGuildQueueMock, createQueue, createInteraction, and queue.node.skipTo when adding the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/bot/src/functions/music/commands/play/index.ts`:
- Around line 38-49: The resolveSearchEngine function (and the related retry
logic handling provider-specific cases) currently falls through to other
providers when a provider was explicitly passed, causing duplicate retries
(e.g., provider='youtube' falling back to auto) and silent cross-provider
resolution; update resolveSearchEngine to return only the requested provider's
QueryType when provider is non-null/defined (no fall-through to default), and
modify the retry ladder logic that picks alternate engines (the code around the
other ranges noted) so cross-provider fallback happens only when provider is
omitted — alternatively ensure the retry picker skips engines already attempted
(track attempted QueryType values) to avoid reusing the same engine twice.
In `@packages/bot/src/functions/music/commands/replay.ts`:
- Around line 21-29: The requireIsPlaying() pre-check is blocking seek
operations while paused; remove the requireIsPlaying() guard from the replay
command (remove the call to requireIsPlaying(...) in replay.ts) and from the
seek command (remove the call to requireIsPlaying(...) in seek.ts) so that
queue.node.seek(...) can be called on paused queues; keep the existing
requireVoiceChannel(...), requireQueue(...), and requireCurrentTrack(...) checks
intact to validate context before calling queue.node.seek(…) and ensure behavior
matches the web handler's seek logic.
In `@packages/bot/src/functions/music/commands/seek.ts`:
- Around line 15-31: parseTimeToMs currently uses parseInt which allows trailing
junk (e.g., "1:30foo" or "90s") to be accepted; change parseTimeToMs to validate
the input exactly before converting by matching the whole string against strict
patterns (e.g., /^\d+$/ for seconds-only and /^\d+:\d{1,2}$/ for
minutes:seconds) and only then parse the numeric parts, ensuring seconds < 60
and all values are non-negative; update the function (parseTimeToMs) to return
null for any input that does not fully match those exact formats so no partial
parses are accepted.
In `@packages/bot/src/functions/music/commands/skipto.ts`:
- Around line 51-68: The code currently calls queue.node.skipTo(targetIndex)
before capturing the intended target track, causing
queue?.tracks.toArray?.()?.[targetIndex] to reference the wrong item; change the
order so you first read and store the intended target track into a local
variable (e.g., targetTrack) using queue?.tracks.toArray?.()?.[targetIndex] or
capturing queue.tracks.get(targetIndex) if available, then call
queue.node.skipTo(targetIndex), and finally use that stored targetTrack when
building the interactionReply/createSuccessEmbed response.
---
Nitpick comments:
In `@packages/bot/src/functions/music/commands/playskip.spec.ts`:
- Around line 53-64: Add an execution-path test in playskip.spec.ts that
exercises playSkipCommand.execute instead of only verifying slash metadata:
invoke playSkipCommand.execute with a mocked command context containing a
"query" option and a fake player/queue, stub the queue mutation and skip methods
(e.g., the queue insertion function and the player's skip/next method), then
assert that the new track was inserted at the front of the queue (index 0) and
that the skip/next method was called once; use test doubles/spies to verify both
the queue mutation and the immediate skip side effect rather than inspecting
internal implementation details.
In `@packages/bot/src/functions/music/commands/playskip.ts`:
- Line 83: The variable "result" declared in the playskip command is never
reassigned; change its declaration from "let result = await
client.player.play(voiceChannel, query, { ... })" to use "const" instead to
reflect immutability and prevent accidental reassignment; update the declaration
where "result" is created in playskip.ts (the client.player.play call) to use
const.
In `@packages/bot/src/functions/music/commands/playtop.spec.ts`:
- Around line 53-64: The test currently only asserts the playTopCommand shape;
add behavioral tests for playTopCommand.execute to ensure it enqueues the new
track at the front and replies with the correct result: mock/stub the
player/queue and a message interaction, call playTopCommand.execute with an
existing queue (and with an empty queue) and assert that the new track appears
at index 0 in the queue and that interaction.reply (or the command's reply
method) is called with the expected success message; reference
playTopCommand.execute and the queue/player mock to locate where to inject these
assertions.
In `@packages/bot/src/functions/music/commands/playtop.ts`:
- Line 84: The variable declaration for result (assigned from client.player.play
in playtop.ts) uses let but is never reassigned; change its declaration to const
to reflect immutability—locate the assignment to result (let result = await
client.player.play(voiceChannel, query, { ... })) and replace let with const so
the variable is read-only.
- Around line 16-34: The helpers isUnknownInteractionError, isUrl, and
resolveSearchEngine are duplicated and should be extracted into a shared
utility; create a new module (e.g., utils/music/searchEngine or utils/general)
that exports isUnknownInteractionError, isUrl, and the enhanced
resolveSearchEngine signature (accepting query and optional provider like the
version in play/index.ts), replace the local definitions in playtop.ts (and
similarly in playskip.ts and play/index.ts) with imports from that module, and
update call sites to use the unified resolveSearchEngine(provider?, query?) API
so all three files reuse the single implementation.
In `@packages/bot/src/functions/music/commands/replay.spec.ts`:
- Around line 59-63: The test currently forces requireCurrentTrack to succeed
globally (requireCurrentTrackMock.mockResolvedValue(true)), which hides the "no
current track" branch; change the specific "no current track" spec to set
requireCurrentTrackMock.mockResolvedValue(false) (while keeping other validators
as needed) and assert that the command returns/early-exits (e.g., checks for the
expected reply or no-op) instead of relying on implementation state; also add a
separate spec that simulates a paused queue by adjusting requireIsPlayingMock
(or the queue mock) to reflect a paused state and assert the paused-queue
behavior once command semantics are finalized.
In `@packages/bot/src/functions/music/commands/skipto.spec.ts`:
- Around line 60-122: Add a new unit test that asserts the command returns early
when queue validation fails by mocking requireQueueMock to resolve false,
calling skiptoCommand.execute with a mocked interaction (use createInteraction)
and a resolved guild queue (resolveGuildQueueMock -> { queue } from
createQueue), and then asserting queue.node.skipTo was not called; target the
same pattern used in the existing voice-channel-failure test and reference
requireQueueMock, skiptoCommand.execute, resolveGuildQueueMock, createQueue,
createInteraction, and queue.node.skipTo when adding the test.
In `@packages/bot/src/functions/music/commands/skipto.ts`:
- Line 52: The optional chaining on queue is unnecessary because requireQueue
ensures queue exists; replace the call queue?.node.skipTo(targetIndex) with a
direct call queue.node.skipTo(targetIndex) in skipto.ts (the code path after
requireQueue) to simplify control flow and remove the redundant ?. Keep the same
targetIndex and error handling unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 213bea6c-7ec7-4284-b3a8-471308495744
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (15)
packages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/queueResolverWiring.spec.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/resume.spec.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/seek.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/skipto.ts
💤 Files with no reviewable changes (2)
- packages/bot/src/functions/music/commands/queueResolverWiring.spec.ts
- packages/bot/src/functions/music/commands/resume.spec.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Quality Gates
- GitHub Check: SonarCloud Scan
- GitHub Check: compressed-size
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{js,jsx,ts,tsx,vue,html}
📄 CodeRabbit inference engine (.cursor/rules/accessibility-openness.mdc)
Provide accessible UI components using semantic HTML and ARIA attributes where necessary
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/dependency-injection.mdc)
**/*.{ts,tsx,js,jsx}: Prefer constructor injection for classes that require dependencies
Avoid global mutable singletons unless necessary
Use explicit interfaces for external dependencies to make testing easier
**/*.{ts,tsx,js,jsx}: Include required references in PRs/code for non-trivial logic: TypeScript (official docs), MDN (JavaScript reference), and official docs for any runtime/framework/libraries used (e.g., Node.js, React) as applicable.
Before assuming behavior of an API, include the doc link and a ≤25-word quote when the change relies on it.
**/*.{ts,tsx,js,jsx}: Prefer named exports for clear usage and easier refactors in TypeScript/JavaScript
Keep import order consistent: external first, then internal modules
Remove dead code and unused imports
**/*.{ts,tsx,js,jsx}: Use PascalCase naming convention for React/UI components
Use camelCase naming convention for variables and functions
Use UPPER_SNAKE_CASE naming convention for constants
Maintain consistent import grouping and ordering within the project, keeping third-party imports separate from local imports
For external data sources (HTTP, database), always validate and sanitize input using type guards or schema validatorsImplement TypeScript typecheck and linter in CI quality checks
**/*.{ts,tsx,js,jsx}: Use TypeScript for enhanced type safety
Implement error handling and error logging
Avoid commenting code unless extremely necessary - code should explain itself with descriptive names
Leave NO todos, placeholders or missing pieces in the code
Variables and functions must use camelCase
Constants must use UPPER_SNAKE_CASE
Use arrow functions for methods and computed properties
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements
Maintain consistent import grouping/order: external imports first, then internal modules
Use named exports for clear usage and easier refactors
Always validate and sanitize external data (HTTP, DB) at the boundary using type guards ...
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
**/*.{js,jsx,ts,tsx}: Never throw strings. ThrowError(or typed subclasses) with descriptive messages
Include causal error ascausewhen available for better debugging
Define clear, stable error codes (e.g.,ERR_AUTH_EXPIRED,ERR_NETWORK_TIMEOUT)
Provide optional metadata (e.g.,details,retryable,status,correlationId) in error objects
Use domain error classes per area (e.g.,AuthenticationError,ValidationError,NetworkError)
Log errors with structure (message, code, stack, cause, correlationId, user context where appropriate)
MarkretryablevsnonRetryableerrors where helpful for operations
Set timeouts and handle aborts/cancellations; avoid dangling requests in API/network code
Implement backoff for transient failures; avoid infinite retries
Map HTTP status → domain errors; 4xx vs 5xx behave differently (e.g., retry for 5xx/network)
**/*.{js,jsx,ts,tsx}: Use functional components with hooks in React/React Native. Avoid class components.
Keep components focused on a single responsibility; extract complex logic into custom hooks.
Keep state local when possible. Use Context/Zustand/Redux only when necessary for state management.
If props or state traverse more than 3 levels, consider using context or a feature-scoped store instead of prop drilling.
Use performance optimization techniques:React.memo,useMemo,useCallback,Suspense(web), and virtualization for long lists; avoid unnecessary re-renders.
Web accessibility: use semantic HTML, labels, focus management, keyboard navigation, andaria-*attributes as needed.
React Native accessibility: use accessibility props (accessible,accessibilityLabel), proper roles and labels.
Identify and extract repetitive UI components proactively tocomponents/with clear props and minimal coupling.
Web styles: prefer co-located styles or design system tokens; avoid global style leakage.
React Native styles: preferStyleSheet.create, design tokens, and theme providers; avoid in...
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
**/index.ts
📄 CodeRabbit inference engine (.cursor/rules/pattern.mdc)
Use
index.tsonly to re-export a small, intentional surface per module
Files:
packages/bot/src/functions/music/commands/play/index.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pattern.mdc)
Introduce interfaces at module boundaries to enable testing and substitutions
**/*.{ts,tsx}: Avoid usinganytype in TypeScript. If unavoidable, useunknownwith type guards and justify with a code comment
Preferinterfacefor defining public object shapes in TypeScript, usetypefor unions and utility types
Use TypeScript utility types such asPartial,Pick,Omit,Readonly, andRecordwhen appropriate
UseI{Name}naming convention for interfaces in TypeScript
UseT{Name}naming convention for type aliases and utility types in TypeScript
**/*.{ts,tsx}: Prefer types over interfaces for most cases
Don't ever useany- type safety always
Avoid enums; use const objects instead
For complex types, create a separate file to declare them and import them
Avoid usinganytype; if unavoidable, useunknownwith type guards and justify with code comment
Preferinterfacefor public API shapes; usetypefor unions and utility types
Use TypeScript utility types (Partial, Pick, Omit, Readonly, Record)
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/documentation.mdc)
**/*.{js,ts,tsx,jsx}: Minimize comments in code; explain the 'why' when non-obvious, let code express the 'what' through clear naming
Document trade-offs briefly when deviating from ideal patterns
**/*.{js,ts,tsx,jsx}: Store secrets, ports, and hosts in environment variables (.env,.env.example) and never hardcode them
Avoid redundant or decorative AI comments; code should be self-explanatory and only commented when logic is non-obvious; prefer refactoring over lengthy comments
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
packages/bot/src/functions/*/commands/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/lucky-discord-bot.mdc)
packages/bot/src/functions/*/commands/**/*.{ts,tsx}: Command model must includedata(slash builder),execute, andcategoryproperties exported frompackages/bot/src/models/Command.ts
Use@discordjs/buildersfor building thedata(SlashCommandBuilder) in command definitions
Commandexecutefunction must receive{ interaction, client }parameters fromCommandExecuteParamstype
UseinteractionReplyandcreateUserFriendlyErrorutilities from@lucky/shared/generalutils for command replies and error handling
Use existing validators frompackages/bot/src/utils/command/for voice channel, queue, and guild validations in commands
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
packages/bot/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/lucky-discord-bot.mdc)
packages/bot/**/*.{ts,tsx}: UseuseMainPlayer()fromdiscord-playerto access the player instance; do not instantiate player directly
Do not duplicate queue or player state outside Discord Player; use shared services from@lucky/sharedfor persistent data like track history and session information
UseerrorLoganddebugLogfrom@lucky/shared/utilsfor logging throughout the bot package
Use embed and reply utilities from@lucky/sharedfor consistent message formatting and error sanitization across the bot
Use services from@lucky/shared(DatabaseService, Redis client) for database and cache access; do not instantiate Prisma or Redis directly in the bot package
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
packages/bot/**
📄 CodeRabbit inference engine (.cursor/rules/lucky-project.mdc)
The
botpackage depends onsharedand contains Discord bot commands and player handlers using Discord.js and Discord Player
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
**/*.{js,mjs,ts,mts}
📄 CodeRabbit inference engine (.cursor/rules/lucky-project.mdc)
Use Node.js version ≥22 with ESM (ECMAScript modules) only; no CommonJS
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
packages/bot/src/functions/{general,music,download}/commands/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/subagent-discord.mdc)
packages/bot/src/functions/{general,music,download}/commands/**/*.ts: Apply.cursor/rules/lucky-discord-bot.mdcrules for Discord bot commands and player implementation
Use.cursor/skills/discord-commands/SKILL.mdfor implementing slash commands
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
packages/bot/src/functions/music/commands/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/subagent-discord.mdc)
Use
.cursor/skills/music-queue-player/SKILL.mdfor play, queue, skip, volume commands and player lifecycle management
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
packages/bot/src/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/subagent-discord.mdc)
Use
@lucky/sharedfor database, Redis, logging, and embed utilities instead of implementing them locally
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
packages/bot/src/functions/music/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/subagent-discord.mdc)
Use existing voice/queue/guild validators before manipulating player or queue state
Files:
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/pause.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/replay.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/playtop.tspackages/bot/src/functions/music/commands/seek.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/skipto.tspackages/bot/src/functions/music/commands/seek.ts
**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/frontend.mdc)
**/*.{test,spec}.{js,jsx,ts,tsx}: Test behavior, not implementation. Prefer Testing Library utilities for testing React/React Native components.
For React Native tests: mock native modules and test component interactions and accessibility labels.
Files:
packages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/seek.spec.ts
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/pattern.mdc)
**/*.{test,spec}.{ts,tsx,js,jsx}: Test behavior, not implementation details
Prefer unit tests for core logic; add integration tests at meaningful boundaries
Files:
packages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/seek.spec.ts
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/testing-quality.mdc)
**/*.{test,spec}.{js,ts,jsx,tsx}: Use Jest + a React testing library for unit and component tests as applicable
Test behavior, not implementation details
Files:
packages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/seek.spec.ts
**/*.{spec,test}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/quality.mdc)
**/*.{spec,test}.{ts,tsx,js,jsx}: Use Jest for unit and integration tests
Test behavior, not implementation details
Run unit, integration tests, and coverage report in CI quality checks
Files:
packages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/seek.spec.ts
**/*.spec.ts
📄 CodeRabbit inference engine (.cursor/rules/quality.mdc)
Unit tests must use naming convention
*.spec.ts
Files:
packages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/replay.spec.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/skipto.spec.tspackages/bot/src/functions/music/commands/pause.spec.tspackages/bot/src/functions/music/commands/seek.spec.ts
🔇 Additional comments (7)
packages/bot/src/functions/music/commands/pause.ts (1)
25-35: Nice toggle-state handling.Using the pre-toggle
isPausedvalue for both the node action and the reply label keeps the embed text aligned with what actually happened.Also applies to: 51-52
packages/bot/src/functions/music/commands/pause.spec.ts (1)
84-128: Nice coverage of both toggle directions.The paused/playing plus current-track/no-track matrix should catch most regressions in the new pause/resume semantics.
packages/bot/src/functions/music/commands/seek.ts (1)
57-59: RemoverequireIsPlaying()to allow seeking on paused tracks.Line 59 blocks paused queues from seeking. Since the
/pausecommand allows toggling on any queue state and the web handler seeks without anisPlayingcheck, paused queues with a currentTrack should be seekable. Remove this validation to enable the pause → seek → resume flow.packages/bot/src/functions/music/commands/playskip.ts (2)
17-33: Duplicate helper functions (same issue as playtop.ts).These helper functions are identical to those in
playtop.ts. See the comment onplaytop.tslines 16-34 for the recommended refactor to extract these to a shared utility.
109-114: Queue manipulation and skip logic looks correct.The sequence of removing the track from its default position, inserting at index 0, then calling
skip()should correctly play the newly added track immediately. The conditional check ensures this only happens when there are existing tracks in the queue.packages/bot/src/functions/music/commands/playtop.ts (1)
110-114: LGTM on queue manipulation logic.The approach of removing the track from its default position and reinserting at index 0 correctly places the new track at the front of the queue. The conditional
tracks.length > 0appropriately handles the edge case of an empty queue.packages/bot/src/functions/music/commands/seek.spec.ts (1)
61-138: Good test coverage with comprehensive edge cases.The test suite effectively covers the key behaviors: time format parsing (mm:ss and ss), validation errors (invalid format, out of range, non-seekable tracks), and early return on voice channel validation failure. The mock setup follows the established pattern used across other music command tests.
Consider adding tests for the other validation failures (
requireQueue,requireCurrentTrack,requireIsPlaying) for completeness, though the current coverage captures the most critical paths.
| function resolveSearchEngine(query: string, provider?: string | null): QueryType { | ||
| if (isUrl(query)) return QueryType.AUTO | ||
| return QueryType.SPOTIFY_SEARCH | ||
|
|
||
| switch (provider) { | ||
| case 'youtube': | ||
| return QueryType.YOUTUBE_SEARCH | ||
| case 'soundcloud': | ||
| return QueryType.SOUNDCLOUD_SEARCH | ||
| case 'spotify': | ||
| default: | ||
| return QueryType.SPOTIFY_SEARCH | ||
| } |
There was a problem hiding this comment.
Don't fall through to other providers when provider was explicitly chosen.
With the new option, provider becomes user intent. The existing retry ladder still behaves like “Spotify → YouTube → auto”, so provider='youtube' retries the same engine twice and provider='soundcloud' can silently resolve from a different source. I’d only use cross-provider fallback when provider is omitted, or skip search engines that were already attempted.
Also applies to: 79-89, 121-147
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/bot/src/functions/music/commands/play/index.ts` around lines 38 -
49, The resolveSearchEngine function (and the related retry logic handling
provider-specific cases) currently falls through to other providers when a
provider was explicitly passed, causing duplicate retries (e.g.,
provider='youtube' falling back to auto) and silent cross-provider resolution;
update resolveSearchEngine to return only the requested provider's QueryType
when provider is non-null/defined (no fall-through to default), and modify the
retry ladder logic that picks alternate engines (the code around the other
ranges noted) so cross-provider fallback happens only when provider is omitted —
alternatively ensure the retry picker skips engines already attempted (track
attempted QueryType values) to avoid reusing the same engine twice.
| if (!(await requireVoiceChannel(interaction))) return | ||
|
|
||
| const { queue } = resolveGuildQueue(client, interaction.guildId ?? '') | ||
|
|
||
| if (!(await requireQueue(queue, interaction))) return | ||
| if (!(await requireCurrentTrack(queue, interaction))) return | ||
| if (!(await requireIsPlaying(queue, interaction))) return | ||
|
|
||
| if (queue !== null && queue !== undefined && !queue.node.isPaused()) { | ||
| await interactionReply({ | ||
| interaction, | ||
| content: { | ||
| embeds: [ | ||
| createWarningEmbed( | ||
| 'Already playing', | ||
| '▶️ Music is already playing.', | ||
| ), | ||
| ], | ||
| ephemeral: true, | ||
| }, | ||
| }) | ||
| return | ||
| } | ||
|
|
||
| queue?.node.resume() | ||
| queue?.node.seek(0) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find and examine the replay.ts file
find . -type f -name "replay.ts" | head -5Repository: LucasSantana-Dev/Lucky
Length of output: 119
🏁 Script executed:
# Find the webMusic command handler file
find . -type f -path "*webMusic/commandHandlers.ts"Repository: LucasSantana-Dev/Lucky
Length of output: 121
🏁 Script executed:
# Check for discord-player documentation or type definitions to understand seek behavior on paused queues
find . -type f -name "*.ts" -o -name "*.d.ts" | xargs rg -l "discord-player" | head -10Repository: LucasSantana-Dev/Lucky
Length of output: 579
🏁 Script executed:
# Read replay.ts to understand the full structure
cat -n ./packages/bot/src/functions/music/commands/replay.ts | head -40Repository: LucasSantana-Dev/Lucky
Length of output: 1985
🏁 Script executed:
# Read webMusic handler to see seek without paused gate
cat -n ./packages/bot/src/handlers/webMusic/commandHandlers.ts | sed -n '155,180p'Repository: LucasSantana-Dev/Lucky
Length of output: 851
🏁 Script executed:
# Find and read the commandValidations file to see what requireIsPlaying does
find . -type f -path "*utils/command/commandValidations*"Repository: LucasSantana-Dev/Lucky
Length of output: 182
🏁 Script executed:
# Read the validator implementations
cat -n ./packages/bot/src/utils/command/commandValidations.ts | head -100Repository: LucasSantana-Dev/Lucky
Length of output: 3627
🏁 Script executed:
# Continue reading to find requireIsPlaying
cat -n ./packages/bot/src/utils/command/commandValidations.ts | sed -n '100,150p'Repository: LucasSantana-Dev/Lucky
Length of output: 1795
🏁 Script executed:
# Check if there's a pause/resume handler or logic to understand queue state
rg -A 5 -B 2 "isPlaying|seek" ./packages/bot/src/handlers/webMusic/commandHandlers.ts | head -50Repository: LucasSantana-Dev/Lucky
Length of output: 526
🏁 Script executed:
# Look for pause/resume command handlers
rg -l "pause|resume" ./packages/bot/src/functions/music/commands/*.tsRepository: LucasSantana-Dev/Lucky
Length of output: 248
🏁 Script executed:
# Read the pause command to understand pause/resume flow
cat -n ./packages/bot/src/functions/music/commands/pause.tsRepository: LucasSantana-Dev/Lucky
Length of output: 2361
🏁 Script executed:
# Search for how discord-player queue.node.seek behaves on paused queues
# Check the discord-player package or type definitions if available
find . -type f -name "*.json" | xargs grep -l "discord-player" | head -3Repository: LucasSantana-Dev/Lucky
Length of output: 128
🏁 Script executed:
# Check package.json to see discord-player version
cat ./packages/bot/package.json | grep -A 2 -B 2 "discord-player"Repository: LucasSantana-Dev/Lucky
Length of output: 438
🏁 Script executed:
# Search for other uses of seek in the codebase to understand expected behavior
rg "\.seek\(" --type ts -B 2 -A 2Repository: LucasSantana-Dev/Lucky
Length of output: 3530
🏁 Script executed:
# Read seek.ts to see what validations it uses
cat -n ./packages/bot/src/functions/music/commands/seek.ts | head -50Repository: LucasSantana-Dev/Lucky
Length of output: 2223
🏁 Script executed:
# Continue reading seek.ts to see execute function
cat -n ./packages/bot/src/functions/music/commands/seek.ts | sed -n '50,85p'Repository: LucasSantana-Dev/Lucky
Length of output: 1578
Both /replay and /seek are blocked in paused state.
Both commands use requireIsPlaying() before calling queue.node.seek(), rejecting paused queues. This breaks the pause → replay workflow and diverges from the web handler (packages/bot/src/handlers/webMusic/commandHandlers.ts:166-173), which allows seek without this gate. Discord Player's seek() operation should work on paused queues (it only changes position, not play state). Remove requireIsPlaying() from both replay.ts (line 27) and seek.ts (line 59).
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/bot/src/functions/music/commands/replay.ts` around lines 21 - 29,
The requireIsPlaying() pre-check is blocking seek operations while paused;
remove the requireIsPlaying() guard from the replay command (remove the call to
requireIsPlaying(...) in replay.ts) and from the seek command (remove the call
to requireIsPlaying(...) in seek.ts) so that queue.node.seek(...) can be called
on paused queues; keep the existing requireVoiceChannel(...), requireQueue(...),
and requireCurrentTrack(...) checks intact to validate context before calling
queue.node.seek(…) and ensure behavior matches the web handler's seek logic.
| function parseTimeToMs(timeStr: string): number | null { | ||
| const parts = timeStr.split(':') | ||
|
|
||
| if (parts.length === 1) { | ||
| const seconds = parseInt(parts[0], 10) | ||
| return !isNaN(seconds) && seconds >= 0 ? seconds * 1000 : null | ||
| } | ||
|
|
||
| if (parts.length === 2) { | ||
| const minutes = parseInt(parts[0], 10) | ||
| const seconds = parseInt(parts[1], 10) | ||
| return !isNaN(minutes) && !isNaN(seconds) && minutes >= 0 && seconds >= 0 && seconds < 60 | ||
| ? (minutes * 60 + seconds) * 1000 | ||
| : null | ||
| } | ||
|
|
||
| return null |
There was a problem hiding this comment.
Reject partial parses in parseTimeToMs().
parseInt() accepts trailing junk, so inputs like 1:30foo and 90s currently pass validation and seek to a value the user did not actually enter. This should do an exact format check before converting.
Possible fix
function parseTimeToMs(timeStr: string): number | null {
- const parts = timeStr.split(':')
-
- if (parts.length === 1) {
- const seconds = parseInt(parts[0], 10)
- return !isNaN(seconds) && seconds >= 0 ? seconds * 1000 : null
- }
-
- if (parts.length === 2) {
- const minutes = parseInt(parts[0], 10)
- const seconds = parseInt(parts[1], 10)
- return !isNaN(minutes) && !isNaN(seconds) && minutes >= 0 && seconds >= 0 && seconds < 60
- ? (minutes * 60 + seconds) * 1000
- : null
- }
-
- return null
+ const normalized = timeStr.trim()
+ if (/^\d+$/.test(normalized)) return Number(normalized) * 1000
+
+ const match = normalized.match(/^(\d+):(\d{1,2})$/)
+ if (!match) return null
+
+ const minutes = Number(match[1])
+ const seconds = Number(match[2])
+ return seconds < 60 ? (minutes * 60 + seconds) * 1000 : null
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| function parseTimeToMs(timeStr: string): number | null { | |
| const parts = timeStr.split(':') | |
| if (parts.length === 1) { | |
| const seconds = parseInt(parts[0], 10) | |
| return !isNaN(seconds) && seconds >= 0 ? seconds * 1000 : null | |
| } | |
| if (parts.length === 2) { | |
| const minutes = parseInt(parts[0], 10) | |
| const seconds = parseInt(parts[1], 10) | |
| return !isNaN(minutes) && !isNaN(seconds) && minutes >= 0 && seconds >= 0 && seconds < 60 | |
| ? (minutes * 60 + seconds) * 1000 | |
| : null | |
| } | |
| return null | |
| function parseTimeToMs(timeStr: string): number | null { | |
| const normalized = timeStr.trim() | |
| if (/^\d+$/.test(normalized)) return Number(normalized) * 1000 | |
| const match = normalized.match(/^(\d+):(\d{1,2})$/) | |
| if (!match) return null | |
| const minutes = Number(match[1]) | |
| const seconds = Number(match[2]) | |
| return seconds < 60 ? (minutes * 60 + seconds) * 1000 : null | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/bot/src/functions/music/commands/seek.ts` around lines 15 - 31,
parseTimeToMs currently uses parseInt which allows trailing junk (e.g.,
"1:30foo" or "90s") to be accepted; change parseTimeToMs to validate the input
exactly before converting by matching the whole string against strict patterns
(e.g., /^\d+$/ for seconds-only and /^\d+:\d{1,2}$/ for minutes:seconds) and
only then parse the numeric parts, ensuring seconds < 60 and all values are
non-negative; update the function (parseTimeToMs) to return null for any input
that does not fully match those exact formats so no partial parses are accepted.
| const targetIndex = position - 1 | ||
| queue?.node.skipTo(targetIndex) | ||
|
|
||
| const targetTrack = queue?.tracks.toArray?.()?.[targetIndex] | ||
| if (!targetTrack) { | ||
| await interactionReply({ | ||
| interaction, | ||
| content: { | ||
| embeds: [ | ||
| createSuccessEmbed( | ||
| '⏭️ Skipped', | ||
| `Skipped to position ${position}.`, | ||
| ), | ||
| ], | ||
| }, | ||
| }) | ||
| return | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
discord-player node.skipTo behavior queue tracks after skip
💡 Result:
In discord-player, queue.node.skipTo(track) skips to the specified track (TrackResolvable: Track, string ID, or number index), removing all tracks before it from the queue. Tracks after the target remain intact and will play sequentially afterward. Example from docs: // Skip to track at index 5, removing tracks 0-4 if (queue.node.skipTo(5)) { await interaction.reply('Skipped to track 6!'); } The target track becomes the new current track, and the queue continues with subsequent tracks. This differs from queue.node.jump(track), which moves the target to the front without removing preceding tracks. No reported bugs with skipTo behavior in recent versions (as of 2026). Past issues were with skip or jump.
Citations:
- 1: https://mintlify.com/androz2091/discord-player/api/guild-queue-player-node
- 2: https://discord-player.js.org/api/discord-player/classes/GuildQueuePlayerNode
- 3: Running .skip will skips the current song and also the next song in the queue. Androz2091/discord-player#1512
- 4: <Queue>.jump not working properly Androz2091/discord-player#711
- 5: player.skipTo feature suggestion Androz2091/discord-player#760
- 6: .jump() broke Androz2091/discord-player#744
Capture target track before skipTo to prevent retrieving the wrong track.
After queue.node.skipTo(targetIndex) executes, the queue state changes—tracks preceding the target are removed, and the target track becomes currentTrack. Accessing queue.tracks.toArray()[targetIndex] after the skip will return a different track (or undefined) because the array has shifted. The target track must be captured before the skip call.
Proposed fix
const targetIndex = position - 1
+ const targetTrack = queue?.tracks.toArray?.()?.[targetIndex]
queue?.node.skipTo(targetIndex)
- const targetTrack = queue?.tracks.toArray?.()?.[targetIndex]
if (!targetTrack) {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const targetIndex = position - 1 | |
| queue?.node.skipTo(targetIndex) | |
| const targetTrack = queue?.tracks.toArray?.()?.[targetIndex] | |
| if (!targetTrack) { | |
| await interactionReply({ | |
| interaction, | |
| content: { | |
| embeds: [ | |
| createSuccessEmbed( | |
| '⏭️ Skipped', | |
| `Skipped to position ${position}.`, | |
| ), | |
| ], | |
| }, | |
| }) | |
| return | |
| } | |
| const targetIndex = position - 1 | |
| const targetTrack = queue?.tracks.toArray?.()?.[targetIndex] | |
| queue?.node.skipTo(targetIndex) | |
| if (!targetTrack) { | |
| await interactionReply({ | |
| interaction, | |
| content: { | |
| embeds: [ | |
| createSuccessEmbed( | |
| '⏭️ Skipped', | |
| `Skipped to position ${position}.`, | |
| ), | |
| ], | |
| }, | |
| }) | |
| return | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/bot/src/functions/music/commands/skipto.ts` around lines 51 - 68,
The code currently calls queue.node.skipTo(targetIndex) before capturing the
intended target track, causing queue?.tracks.toArray?.()?.[targetIndex] to
reference the wrong item; change the order so you first read and store the
intended target track into a local variable (e.g., targetTrack) using
queue?.tracks.toArray?.()?.[targetIndex] or capturing
queue.tracks.get(targetIndex) if available, then call
queue.node.skipTo(targetIndex), and finally use that stored targetTrack when
building the interactionReply/createSuccessEmbed response.
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/bot/src/functions/music/commands/playtop.spec.ts (1)
101-101: Reduceanyusage in test helpers/invocationsThese casts/types hide contract drift between command execute params and mocks. Prefer typed helper aliases (
unknown+ narrow, or explicit test-local types) instead ofany.As per coding guidelines, "Don't ever use
any- type safety always".Also applies to: 109-109, 124-124, 142-142, 167-167, 188-188, 202-202, 231-231
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/bot/src/functions/music/commands/playtop.spec.ts` at line 101, The tests use casts to any (e.g., the options array lookup that assigns const queryOption = options.find((opt: any) => opt.name === 'query')), which hides type drift; replace those any usages by declaring a small test-local type for the option shape (e.g., type TestOption = { name: string; value?: string } or use unknown and narrow) and use that type in the find callback and other similar spots (lines referencing options, queryOption, etc.) so the test helpers/assertions are statically typed and you avoid any; update all occurrences flagged (around the queryOption and the other listed lines) to use the test-local type or unknown+type-guard narrowing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/bot/src/functions/music/commands/play/queryUtils.ts`:
- Around line 55-59: Replace the direct call to interaction.reply in the guild
check with the shared utilities: use interactionReply(...) instead of
interaction.reply and build the message with createUserFriendlyError (import
from `@lucky/shared/general`) so replies go through centralized handling; locate
the guild check in queryUtils.ts (the block using interaction.guildId and
createErrorEmbed) and swap to interactionReply(interaction,
createUserFriendlyError(...)) ensuring the function imports are added/updated.
- Around line 63-67: The code casts interaction.member to GuildMember and
accesses member.voice.channel after calling requireVoiceChannel, but
requireVoiceChannel only returns boolean and does not narrow types; add an
explicit guard to check interaction.member is present before casting (e.g., if
(!interaction.member) return) or change requireVoiceChannel into a proper type
guard that narrows interaction.member to GuildMember so the subsequent access to
member.voice.channel (voiceChannel) is safe; update the code paths around
requireVoiceChannel, interaction.member, and any usage of voiceChannel
accordingly.
In `@packages/bot/src/functions/music/commands/playtop.spec.ts`:
- Line 216: The test title in playtop.spec.ts is misleading: rename the it(...)
description from "shows nowPlaying embed on success" to reflect the actual
assertion checking { kind: 'addedToQueue' } (e.g., "shows addedToQueue embed on
success" or similar). Locate the failing test's it(...) block in the
playtop.spec.ts file and update the test name string to match the asserted
behavior (reference the assertion that expects kind: 'addedToQueue').
---
Nitpick comments:
In `@packages/bot/src/functions/music/commands/playtop.spec.ts`:
- Line 101: The tests use casts to any (e.g., the options array lookup that
assigns const queryOption = options.find((opt: any) => opt.name === 'query')),
which hides type drift; replace those any usages by declaring a small test-local
type for the option shape (e.g., type TestOption = { name: string; value?:
string } or use unknown and narrow) and use that type in the find callback and
other similar spots (lines referencing options, queryOption, etc.) so the test
helpers/assertions are statically typed and you avoid any; update all
occurrences flagged (around the queryOption and the other listed lines) to use
the test-local type or unknown+type-guard narrowing.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: efc5e7e8-4b0e-421d-b278-2c82728de243
📒 Files selected for processing (6)
packages/bot/src/functions/music/commands/play/index.tspackages/bot/src/functions/music/commands/play/queryUtils.tspackages/bot/src/functions/music/commands/playskip.spec.tspackages/bot/src/functions/music/commands/playskip.tspackages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/playtop.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/bot/src/functions/music/commands/playskip.ts
- packages/bot/src/functions/music/commands/playskip.spec.ts
- packages/bot/src/functions/music/commands/playtop.ts
- packages/bot/src/functions/music/commands/play/index.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: SonarCloud Scan
- GitHub Check: compressed-size
- GitHub Check: Quality Gates
🧰 Additional context used
📓 Path-based instructions (18)
**/*.{js,jsx,ts,tsx,vue,html}
📄 CodeRabbit inference engine (.cursor/rules/accessibility-openness.mdc)
Provide accessible UI components using semantic HTML and ARIA attributes where necessary
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/dependency-injection.mdc)
**/*.{ts,tsx,js,jsx}: Prefer constructor injection for classes that require dependencies
Avoid global mutable singletons unless necessary
Use explicit interfaces for external dependencies to make testing easier
**/*.{ts,tsx,js,jsx}: Include required references in PRs/code for non-trivial logic: TypeScript (official docs), MDN (JavaScript reference), and official docs for any runtime/framework/libraries used (e.g., Node.js, React) as applicable.
Before assuming behavior of an API, include the doc link and a ≤25-word quote when the change relies on it.
**/*.{ts,tsx,js,jsx}: Prefer named exports for clear usage and easier refactors in TypeScript/JavaScript
Keep import order consistent: external first, then internal modules
Remove dead code and unused imports
**/*.{ts,tsx,js,jsx}: Use PascalCase naming convention for React/UI components
Use camelCase naming convention for variables and functions
Use UPPER_SNAKE_CASE naming convention for constants
Maintain consistent import grouping and ordering within the project, keeping third-party imports separate from local imports
For external data sources (HTTP, database), always validate and sanitize input using type guards or schema validatorsImplement TypeScript typecheck and linter in CI quality checks
**/*.{ts,tsx,js,jsx}: Use TypeScript for enhanced type safety
Implement error handling and error logging
Avoid commenting code unless extremely necessary - code should explain itself with descriptive names
Leave NO todos, placeholders or missing pieces in the code
Variables and functions must use camelCase
Constants must use UPPER_SNAKE_CASE
Use arrow functions for methods and computed properties
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements
Maintain consistent import grouping/order: external imports first, then internal modules
Use named exports for clear usage and easier refactors
Always validate and sanitize external data (HTTP, DB) at the boundary using type guards ...
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-handling.mdc)
**/*.{js,jsx,ts,tsx}: Never throw strings. ThrowError(or typed subclasses) with descriptive messages
Include causal error ascausewhen available for better debugging
Define clear, stable error codes (e.g.,ERR_AUTH_EXPIRED,ERR_NETWORK_TIMEOUT)
Provide optional metadata (e.g.,details,retryable,status,correlationId) in error objects
Use domain error classes per area (e.g.,AuthenticationError,ValidationError,NetworkError)
Log errors with structure (message, code, stack, cause, correlationId, user context where appropriate)
MarkretryablevsnonRetryableerrors where helpful for operations
Set timeouts and handle aborts/cancellations; avoid dangling requests in API/network code
Implement backoff for transient failures; avoid infinite retries
Map HTTP status → domain errors; 4xx vs 5xx behave differently (e.g., retry for 5xx/network)
**/*.{js,jsx,ts,tsx}: Use functional components with hooks in React/React Native. Avoid class components.
Keep components focused on a single responsibility; extract complex logic into custom hooks.
Keep state local when possible. Use Context/Zustand/Redux only when necessary for state management.
If props or state traverse more than 3 levels, consider using context or a feature-scoped store instead of prop drilling.
Use performance optimization techniques:React.memo,useMemo,useCallback,Suspense(web), and virtualization for long lists; avoid unnecessary re-renders.
Web accessibility: use semantic HTML, labels, focus management, keyboard navigation, andaria-*attributes as needed.
React Native accessibility: use accessibility props (accessible,accessibilityLabel), proper roles and labels.
Identify and extract repetitive UI components proactively tocomponents/with clear props and minimal coupling.
Web styles: prefer co-located styles or design system tokens; avoid global style leakage.
React Native styles: preferStyleSheet.create, design tokens, and theme providers; avoid in...
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
**/*.{test,spec}.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/frontend.mdc)
**/*.{test,spec}.{js,jsx,ts,tsx}: Test behavior, not implementation. Prefer Testing Library utilities for testing React/React Native components.
For React Native tests: mock native modules and test component interactions and accessibility labels.
Files:
packages/bot/src/functions/music/commands/playtop.spec.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/pattern.mdc)
Introduce interfaces at module boundaries to enable testing and substitutions
**/*.{ts,tsx}: Avoid usinganytype in TypeScript. If unavoidable, useunknownwith type guards and justify with a code comment
Preferinterfacefor defining public object shapes in TypeScript, usetypefor unions and utility types
Use TypeScript utility types such asPartial,Pick,Omit,Readonly, andRecordwhen appropriate
UseI{Name}naming convention for interfaces in TypeScript
UseT{Name}naming convention for type aliases and utility types in TypeScript
**/*.{ts,tsx}: Prefer types over interfaces for most cases
Don't ever useany- type safety always
Avoid enums; use const objects instead
For complex types, create a separate file to declare them and import them
Avoid usinganytype; if unavoidable, useunknownwith type guards and justify with code comment
Preferinterfacefor public API shapes; usetypefor unions and utility types
Use TypeScript utility types (Partial, Pick, Omit, Readonly, Record)
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/pattern.mdc)
**/*.{test,spec}.{ts,tsx,js,jsx}: Test behavior, not implementation details
Prefer unit tests for core logic; add integration tests at meaningful boundaries
Files:
packages/bot/src/functions/music/commands/playtop.spec.ts
**/*.{test,spec}.{js,ts,jsx,tsx}
📄 CodeRabbit inference engine (.cursor/rules/testing-quality.mdc)
**/*.{test,spec}.{js,ts,jsx,tsx}: Use Jest + a React testing library for unit and component tests as applicable
Test behavior, not implementation details
Files:
packages/bot/src/functions/music/commands/playtop.spec.ts
**/*.{js,ts,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/documentation.mdc)
**/*.{js,ts,tsx,jsx}: Minimize comments in code; explain the 'why' when non-obvious, let code express the 'what' through clear naming
Document trade-offs briefly when deviating from ideal patterns
**/*.{js,ts,tsx,jsx}: Store secrets, ports, and hosts in environment variables (.env,.env.example) and never hardcode them
Avoid redundant or decorative AI comments; code should be self-explanatory and only commented when logic is non-obvious; prefer refactoring over lengthy comments
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
packages/bot/src/functions/*/commands/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/lucky-discord-bot.mdc)
packages/bot/src/functions/*/commands/**/*.{ts,tsx}: Command model must includedata(slash builder),execute, andcategoryproperties exported frompackages/bot/src/models/Command.ts
Use@discordjs/buildersfor building thedata(SlashCommandBuilder) in command definitions
Commandexecutefunction must receive{ interaction, client }parameters fromCommandExecuteParamstype
UseinteractionReplyandcreateUserFriendlyErrorutilities from@lucky/shared/generalutils for command replies and error handling
Use existing validators frompackages/bot/src/utils/command/for voice channel, queue, and guild validations in commands
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
packages/bot/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/lucky-discord-bot.mdc)
packages/bot/**/*.{ts,tsx}: UseuseMainPlayer()fromdiscord-playerto access the player instance; do not instantiate player directly
Do not duplicate queue or player state outside Discord Player; use shared services from@lucky/sharedfor persistent data like track history and session information
UseerrorLoganddebugLogfrom@lucky/shared/utilsfor logging throughout the bot package
Use embed and reply utilities from@lucky/sharedfor consistent message formatting and error sanitization across the bot
Use services from@lucky/shared(DatabaseService, Redis client) for database and cache access; do not instantiate Prisma or Redis directly in the bot package
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
packages/bot/**
📄 CodeRabbit inference engine (.cursor/rules/lucky-project.mdc)
The
botpackage depends onsharedand contains Discord bot commands and player handlers using Discord.js and Discord Player
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
**/*.{js,mjs,ts,mts}
📄 CodeRabbit inference engine (.cursor/rules/lucky-project.mdc)
Use Node.js version ≥22 with ESM (ECMAScript modules) only; no CommonJS
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
**/*.{spec,test}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/quality.mdc)
**/*.{spec,test}.{ts,tsx,js,jsx}: Use Jest for unit and integration tests
Test behavior, not implementation details
Run unit, integration tests, and coverage report in CI quality checks
Files:
packages/bot/src/functions/music/commands/playtop.spec.ts
**/*.spec.ts
📄 CodeRabbit inference engine (.cursor/rules/quality.mdc)
Unit tests must use naming convention
*.spec.ts
Files:
packages/bot/src/functions/music/commands/playtop.spec.ts
packages/bot/src/functions/{general,music,download}/commands/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/subagent-discord.mdc)
packages/bot/src/functions/{general,music,download}/commands/**/*.ts: Apply.cursor/rules/lucky-discord-bot.mdcrules for Discord bot commands and player implementation
Use.cursor/skills/discord-commands/SKILL.mdfor implementing slash commands
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
packages/bot/src/functions/music/commands/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/subagent-discord.mdc)
Use
.cursor/skills/music-queue-player/SKILL.mdfor play, queue, skip, volume commands and player lifecycle management
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
packages/bot/src/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/subagent-discord.mdc)
Use
@lucky/sharedfor database, Redis, logging, and embed utilities instead of implementing them locally
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
packages/bot/src/functions/music/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/subagent-discord.mdc)
Use existing voice/queue/guild validators before manipulating player or queue state
Files:
packages/bot/src/functions/music/commands/playtop.spec.tspackages/bot/src/functions/music/commands/play/queryUtils.ts
🔇 Additional comments (1)
packages/bot/src/functions/music/commands/play/queryUtils.ts (1)
96-98: No verification needed —queue.node.remove(track)is the official API in discord-player v7.1.0 and will work correctly. Bothqueue.node.remove()andqueue.insertTrack()are supported methods per the discord-player documentation.> Likely an incorrect or invalid review comment.
| if (!interaction.guildId) { | ||
| await interaction.reply({ | ||
| embeds: [createErrorEmbed('Error', 'This command can only be used in a server')], | ||
| ephemeral: true, | ||
| }) |
There was a problem hiding this comment.
Use interactionReply here to avoid uncaught reply failures
Line 56 directly uses interaction.reply(...), which bypasses your centralized reply/error handling path and can throw before the main try/catch flow.
🔧 Suggested fix
- await interaction.reply({
- embeds: [createErrorEmbed('Error', 'This command can only be used in a server')],
- ephemeral: true,
- })
+ await interactionReply({
+ interaction,
+ content: {
+ embeds: [createErrorEmbed('Error', 'This command can only be used in a server')],
+ ephemeral: true,
+ },
+ })As per coding guidelines, "Use interactionReply and createUserFriendlyError utilities from @lucky/shared/general utils for command replies and error handling".
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (!interaction.guildId) { | |
| await interaction.reply({ | |
| embeds: [createErrorEmbed('Error', 'This command can only be used in a server')], | |
| ephemeral: true, | |
| }) | |
| if (!interaction.guildId) { | |
| await interactionReply({ | |
| interaction, | |
| content: { | |
| embeds: [createErrorEmbed('Error', 'This command can only be used in a server')], | |
| ephemeral: true, | |
| }, | |
| }) |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/bot/src/functions/music/commands/play/queryUtils.ts` around lines 55
- 59, Replace the direct call to interaction.reply in the guild check with the
shared utilities: use interactionReply(...) instead of interaction.reply and
build the message with createUserFriendlyError (import from
`@lucky/shared/general`) so replies go through centralized handling; locate the
guild check in queryUtils.ts (the block using interaction.guildId and
createErrorEmbed) and swap to interactionReply(interaction,
createUserFriendlyError(...)) ensuring the function imports are added/updated.
| const member = interaction.member as GuildMember | ||
| if (!(await requireVoiceChannel(interaction))) return | ||
|
|
||
| const voiceChannel = member.voice.channel! | ||
|
|
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Verify whether requireVoiceChannel narrows types or only returns boolean.
rg -n -A30 -B5 'requireVoiceChannel' packages/bot/src/utils/commandRepository: LucasSantana-Dev/Lucky
Length of output: 3564
Guard interaction.member against null/undefined before voice-channel access
requireVoiceChannel returns only a boolean and performs no type narrowing. Although it validates the voice channel exists internally, casting interaction.member to GuildMember on line 63 without first checking if member is null risks a runtime crash if the member is partial or API-shaped. Add an explicit guard like if (!interaction.member) return before line 63, or refactor requireVoiceChannel to return a type guard for safer narrowing.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/bot/src/functions/music/commands/play/queryUtils.ts` around lines 63
- 67, The code casts interaction.member to GuildMember and accesses
member.voice.channel after calling requireVoiceChannel, but requireVoiceChannel
only returns boolean and does not narrow types; add an explicit guard to check
interaction.member is present before casting (e.g., if (!interaction.member)
return) or change requireVoiceChannel into a proper type guard that narrows
interaction.member to GuildMember so the subsequent access to
member.voice.channel (voiceChannel) is safe; update the code paths around
requireVoiceChannel, interaction.member, and any usage of voiceChannel
accordingly.
| expect(errorLog).toHaveBeenCalled() | ||
| }) | ||
|
|
||
| it('shows nowPlaying embed on success', async () => { |
There was a problem hiding this comment.
Test name does not match asserted behavior
Line 216 says “nowPlaying embed on success”, but the expectation at Line 235 checks kind: 'addedToQueue'. Rename the test to match what it validates.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/bot/src/functions/music/commands/playtop.spec.ts` at line 216, The
test title in playtop.spec.ts is misleading: rename the it(...) description from
"shows nowPlaying embed on success" to reflect the actual assertion checking {
kind: 'addedToQueue' } (e.g., "shows addedToQueue embed on success" or similar).
Locate the failing test's it(...) block in the playtop.spec.ts file and update
the test name string to match the asserted behavior (reference the assertion
that expects kind: 'addedToQueue').
…me toggle (#522) * feat(bot): add playtop, playskip, skipto, seek, replay commands and pause/resume toggle * fix(bot): extract shared play utilities and improve test coverage - creates play/queryutils.ts with discord_unknown_interaction_code, isunknowninteractionerror, isurl, and resolvesearchengine - removes duplicate utilities from playtop.ts and playskip.ts - adds comprehensive execute logic tests for playtop and playskip - increases coverage from 2 tests (command structure) to 12+ tests covering error cases, queue operations, and success scenarios - seek.spec.ts already has full test coverage * refactor: extract shared play-at-top logic to reduce duplication
…me toggle (#522) * feat(bot): add playtop, playskip, skipto, seek, replay commands and pause/resume toggle * fix(bot): extract shared play utilities and improve test coverage - creates play/queryutils.ts with discord_unknown_interaction_code, isunknowninteractionerror, isurl, and resolvesearchengine - removes duplicate utilities from playtop.ts and playskip.ts - adds comprehensive execute logic tests for playtop and playskip - increases coverage from 2 tests (command structure) to 12+ tests covering error cases, queue operations, and success scenarios - seek.spec.ts already has full test coverage * refactor: extract shared play-at-top logic to reduce duplication



Summary
Implements 7 music quick wins from Rythm bot parity analysis:
/pausenow toggles between pause and resume (removed/resume)/replay: restarts current track from beginning (seek(0))/seek <time>: jump to position in current track (mm:ssorssformat)/skipto <position>: skip to specific queue position/playtop <query>: add song to front of queue (plays next)/playskip <query>: add to front + immediately skip current track/playprovider param: optionalproviderchoice (spotify/youtube/soundcloud)Test plan
npm run verifypassesSummary by CodeRabbit
New Features
Improvements